const {SET_VIDEO_INFO,SET_VIDEO_INFO_CALLBACK,LOGINUSERID,AES_KEY, AES_IV,GETDEVICETOKEN,DOWNLOADFILE,SAVELOCALFILE, RENDERPROCESSCALL, SCREENSHOTMAC,SCREENSHOTWINDOWS,SCREENCAPTURE,SHOWDIALOG, GET_VIDEO_INFO, SELECT_FILES, DOWNLOAD_PATH, GET_FILE_INFO_CALLBACK, SUPPORT_IMAGE_TYPE,DOWNLOADFILE_CALLBACK} = require("./const/const");
const { ipcMain, dialog,pushNotifications } = require('electron')
// const {  } = require('electron')
const fs = require('fs')
const os = require('os')
const path = require('path')
const url = require('url')
const fetch = require("node-fetch");
const progressStream = require('progress-stream');
const child_process = require('child_process')
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
const FFmpeg = require("fluent-ffmpeg")
const sizeOf = require('image-size')
const FileType = require('file-type')
const ffprobe = require('ffprobe-static');
const execFile = require('child_process').execFile;
const crypto = require("crypto");

const SUPPORT_VIDEO_TYPE = ['mp4', 'mov'];
const setPath = isDev => {
    const ffprobePath = isDev ? ffprobe.path : ffprobe.path.replace('app.asar', 'app.asar.unpacked');
    const formateFfmpegPath = isDev ? ffmpegPath : ffmpegPath.replace('app.asar', 'app.asar.unpacked');
    FFmpeg.setFfprobePath(ffprobePath);
    FFmpeg.setFfmpegPath(formateFfmpegPath);
}

// const aesFileDecry = (url,urlout) => {
//     return new Promise((resolve, reject) => {
//         if(!fs.existsSync(url)){
//             reject("file not exist"+url);
//             return
//         }
//         //throw new Error('test')
//         const input = fs.createReadStream(url);
//         const output = fs.createWriteStream(urlout);
//         const decipher = crypto.createDecipheriv("AES-128-CBC", AES_KEY, AES_IV);
//         input.pipe(decipher).pipe(output);
//         output.on('finish', () => {
//             if(fs.existsSync(url)) fs.rmSync(url)
//             resolve(urlout);
//         });
//         output.on('error', (err) => {
//             reject(err);
//       });
//     });
// }
const _getImageInfo= async (path) =>{
    const { width, height, type } = await sizeOf(path)
    const { size } = fs.statSync(path)
    return {
        width, height, type, size
    }
}
const _getVideoInfo= async (event, filePath,screenshotPath=null)=> {
    let videoDuration, videoSize
    let screenshotName = path.basename(filePath).split('.').shift() + '.png'
    let outpath = DOWNLOAD_PATH;
    if(screenshotPath){
        screenshotName = path.basename(screenshotPath);
        outpath = path.dirname(screenshotPath);
        console.log(screenshotName+"=="+outpath)
    }else{
        screenshotPath = path.resolve(outpath, screenshotName)
    }
    const { ext } = await FileType.fromFile(filePath)
    return new Promise((resolve, reject) => {
        try {
            FFmpeg(filePath)
                .on('end', async (err, info) => {
                    const { width, height, type, size } = await _getImageInfo(screenshotPath)
                    resolve({
                        videoDuration,
                        videoPath: filePath,
                        videoSize,
                        videoType: ext,
                        screenshotPath,
                        screenshotWidth: width,
                        screenshotHeight: height,
                        screenshotType: type,
                        screenshotSize: size,
                    })
                })
                .on('error', (err, info) => {
                    if(event) event.reply('main-process-error', err);
                    reject(err)
                })
                .screenshots({
                    timestamps: [0],
                    filename: screenshotName,
                    folder: outpath
                }).ffprobe((err, metadata) => {
                    if (!err) {
                        videoDuration = metadata.format.duration
                        videoSize = metadata.format.size
                    } else {
                        if(event) event.reply('main-process-error', err);
                        console.log(err)
                    }
                })
        } catch (err) {
            if(event) event.reply('main-process-error', err);
            console.log(err)
        }
    })
}
class IPC {
    win = null;
    downlodPath ="";
    constructor(win) {
        const env = process.env?.NODE_ENV?.trim();
        this.mkDownloadDic(); // Create download file directory
        const isDev = env === 'development';
        setPath(isDev);
        this.win = win;
        process.on('uncaughtException', (error) => {
            // 处理异常
            console.error("未捕获的异常: ", error);
        });
        ipcMain.on(RENDERPROCESSCALL, (event, data) => {
            console.log("get message from render process", event.processId, data)
            const { type, params } = data;
            switch (type) {
                case LOGINUSERID:
                    this.downlodPath = params;
                    if(this.downlodPath.length>0){
                        this.downlodPath= path.resolve(os.homedir(), 'download/'+this.downlodPath);
                        if (!fs.existsSync( this.downlodPath)) {
                            fs.mkdirSync( this.downlodPath)
                        }
                    }
                    break;
                case SHOWDIALOG:
                    this.showDialog();
                    break;
                case SAVELOCALFILE:
                    this.saveFileToLocal(event,params)
                    break;
                case DOWNLOADFILE:
                    this.downloadFilesByUrl(event,params);
                    break;
                case SET_VIDEO_INFO:
                        this.setVideoInfo(event, params);
                        break;
                case GET_VIDEO_INFO:
                    this.getVideoInfo(event, params);
                    break;
                case SELECT_FILES:
                    this.selectFiles(event, params);
                    break;
                case SCREENCAPTURE:
                    this.screenshotMac(event);
                    break;
                case SCREENSHOTWINDOWS:
                    this.screenshotWindows(event);
                    break;
                case GETDEVICETOKEN:
                    this.getDeviceToken(event);
                    break;
            }
        });
    }

    async getDeviceToken(){
        pushNotifications.registerForAPNSNotifications().then((token) => {
            // forward token to your remote notification server
            console.log(token,"device token");
        })
    }
    async screenshotMac(event) {
        const newdate = new Date();
        const date = newdate.toISOString().replaceAll(":","");
        // console.log(date.toISOString());
        let ex = "screencapture -i ~/desktop/screenshot"+date+".png"
        let savePath = process.env.HOME+"/desktop/screenshot"+date+".png"
        child_process.exec(`screencapture -i ~/desktop/screenshot`+date+`.png`,(error, stdout, stderr) => { if (!error) {
            var _img = fs.readFileSync(savePath);
            // console.log(_img);
            event.reply(GET_FILE_INFO_CALLBACK, {
                triggerType: SCREENSHOTMAC,
                data:{_img:_img,savePath}
            })
        }
        });
    }

    async screenshotWindows(event){
        const newdate = new Date();
        const date = newdate.toISOString().replaceAll(":","");
        let url = path.resolve(__dirname, "../Snipaste-2.8.2-Beta-x64/Snipaste.exe");
        let savePath = os.homedir()+"/"+date+".png";
        let command = url+" snip -o "+savePath;
        console.log(command);
        var id = setInterval(dealFile, 300);
        child_process.exec(command,async (error,stdout,stderr)=>{if(!error){
            console.log("done capture");
        }})
        function dealFile(){
            try{
                var _img = fs.readFileSync(savePath);
                clearInterval(id);
                console.log("file exists");
                console.log(_img);
                event.reply(GET_FILE_INFO_CALLBACK, {
                    triggerType: SCREENSHOTMAC,
                    data:{_img:_img,savePath}
                })
            } catch(err){
                if(err.code == 'ENOENT'){
                    // console.log("file doesn't exist yet")
                } else{
                    throw err;
                }
            }   
        }
    }
    showDialog() {
        child_process.exec(`start "" ${path.resolve(os.homedir(), 'download/')}`);
    }
    delDir(path){
        let files = [];
        if(fs.existsSync(path)){
            files = fs.readdirSync(path);
            files.forEach((file, index) => {
                let curPath = path + "/" + file;
                if(fs.statSync(curPath).isDirectory()){
                    delDir(curPath); //递归删除文件夹
                } else {
                    fs.unlinkSync(curPath); //删除文件
                }
            });
            //fs.rmdirSync(path);
        }
    }
    mkdirsSync(dirname) {
        if (fs.existsSync(dirname)) {
            return true;
        } else {
            if (this.mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname);
                return true;
            }
        }
    }
    mkDownloadDic() {
        const downloadDicPath = path.resolve(os.homedir(), 'download/')
        this.mkdirsSync(downloadDicPath)
        // const downTemp =  path.resolve(os.homedir(), 'download/temp/');
        // if(fs.existsSync(downTemp)){
        //     this.delDir(downTemp)
        // }else{
        //     fs.mkdirSync(downTemp);
        // }
    }
     downloadFilesByUrl(event,parm) {
            const {file_url,direct,isDecry} = parm
            const cwd = process.resourcesPath;
            const downloadDicPath = this.downlodPath;

            const file_name = url.parse(file_url).pathname.split('/').pop()
            const file_path = path.resolve(downloadDicPath, file_name)
            const file_path_temp = `${file_path}.tmp`
            if (!fs.existsSync(file_path)) {
                // Create write stream 
                const fileStream = fs.createWriteStream(file_path_temp).on('error', function (e) {
                    console.error('error==>', e)
                }).on('ready', function () {
                    console.log("start download :", file_url);
                }).on('finish', function () {
                    try {
                        // Rename the file after the download is complete
                        // fs.renameSync(file_path_temp, file_path);
                        // console.log('file download complete :', file_path);
                        // event.reply(DOWNLOADFILE_CALLBACK, { file_path,isNew:true})
                        if(fs.existsSync(file_path_temp)){
                            if(isDecry){
                                const input = fs.createReadStream(file_path_temp);
                                const output = fs.createWriteStream(file_path);
                                const decipher = crypto.createDecipheriv("AES-128-CBC", AES_KEY, AES_IV);
                                input.pipe(decipher).pipe(output);
                                output.on('finish', () => {
                                    if(fs.existsSync(file_path_temp)) 
                                        fs.rmSync(file_path_temp)
                                    if(SUPPORT_VIDEO_TYPE.find(v => file_path?.toLocaleLowerCase().includes(v))){
                                          _getVideoInfo(null,file_path,file_path.replace(".mp4",".png"));
                                    }
                                    event.reply(DOWNLOADFILE_CALLBACK, { file_path,isNew:true})
                                });
                            }else{
                                fs.renameSync(file_path_temp, file_path);
                                event.reply(DOWNLOADFILE_CALLBACK, { file_path,isNew:true})
                            }
                        }
                    } catch (err) {
                    }
                });
                // request file
                fetch(file_url, {
                    method: 'GET',
                    headers: { 'Content-Type': 'application/octet-stream' },
                }).then(res => {
                    // Get the file size data in the request header
                    let fsize = res.headers.get("content-length");
                    // Create progress
                    let str = progressStream({
                        length: fsize,
                        time: 100 /* ms */
                    });
                    // Download progress 
                    str.on('progress', function (progressData) {
                        // output without wrapping
                        let percentage = Math.round(progressData.percentage) + '%';
                        console.log(percentage);
                    });
                    res.body.pipe(str).pipe(fileStream);
                }).catch(e => {
                    // Custom exception handling
                    console.log(e);
                });
            } else {
                // existed
                console.log(file_path, 'already exists, do not download')
                event.reply(DOWNLOADFILE_CALLBACK, {file_path,isNew:false })
            }
    }
    async _cvtVideoInfo(event, filePath,isVideo) {
        const { ext } = await FileType.fromFile(filePath);
        let outputFilePath="";
        if(!isVideo){
            if( ext.toLowerCase() =="gif"){
                const outputFile = Date.now() + '_out.gif'
                outputFilePath = path.resolve(DOWNLOAD_PATH,outputFile )
                fs.copyFileSync(filePath,outputFilePath);
                return outputFilePath;
            }
            outputFilePath = path.resolve(DOWNLOAD_PATH,  Date.now() + '_out.jpg')
        }
        else{
            outputFilePath = path.resolve(DOWNLOAD_PATH, Date.now() + '_out.'+ext);
        }
        //console.log(outputFilePath)
        return new Promise((resolve, reject) => {
            try{
                if(isVideo){
                    FFmpeg(filePath)
                    .fps(24)
                    .videoBitrate('400k')
                    .audioBitrate('44k')
                    .on('error', (err, info) => {
                        event.reply('main-process-error', err);
                        reject(err)
                    })
                    .on('end', () => {
                        console.log('Finished processing video');
                        resolve(outputFilePath)
                    })
                    .save(outputFilePath);  //用output,pipe都是不行的
                }else{
                    FFmpeg(filePath)
                    .output(outputFilePath)
                    .withOptions([`-q:v 10`])//,`−vf scale=′min(512, iw):-1'`])
                    .on('end', () => {
                      console.log('压缩完成！');
                      resolve(outputFilePath)
                    })
                    .on('error', (err) => {
                      console.log(`压缩失败：${err.message}`);
                      reject(err)
                    })
                    .run();
                }
            } catch (err) {
                event.reply('main-process-error', err);
                console.log(err);
            }
        });
    }
    async changeVideoToGif(event, filePath){
        const { ext } = await FileType.fromFile(filePath)
        const gifFile = path.resolve(DOWNLOAD_PATH, Date.now().toString()+".gif");
        return new Promise((resolve, reject) => {
            try {
                FFmpeg(filePath)
                .outputOptions(['-pix_fmt rgb24', '-r 3'])
                .videoBitrate('512k')
                .on('end', () => {
                    resolve( gifFile)
                })
                .on('error', (err) => {
                    event.reply('main-process-error', err);
                })
                .save(gifFile);
            } catch (err) {
                event.reply('main-process-error', err);
                console.log(err)
            }
        })
    }

    async getVideoInfo(event, params) {
        const { path,outpath } = params;
        const data = await _getVideoInfo(event, path,outpath)
        // if(!outpath&&data.videoDuration<=10&&data.videoSize< 5 *1024*1024){
        //     let  ndata = {videoDuration:0,size:data.videoSize,type:"gif",name:"new"}
        //     ndata.path = await this.changeVideoToGif(event,path);
        //     event.reply("GET_VIDEO_INFO_CALLBACK", {data:ndata})
        //     return;
        // }
        event.reply("GET_VIDEO_INFO_CALLBACK", { data })
    }
    async setVideoInfo(event, params) {
        const { path,isVideo} = params;
        const data = await this._cvtVideoInfo(event, path,isVideo)
        event.reply(SET_VIDEO_INFO_CALLBACK, data)
    }
    async saveFileToLocal(event, file){
        if(fs.existsSync(file)){
            const { ext } = await FileType.fromFile(file);
            console.log(ext)
            const saveFilePath = dialog.showSaveDialogSync({defaultPath:file, filters:[{name:ext,extensions:[ext]}] } );
            if (!saveFilePath) return; // 如果用户取消了保存操作，则返回

            fs.copyFileSync(file,saveFilePath);
        }
    }
    async selectFiles(event, params) {
        const { extensions, fileType, multiSelections } = params
        const [filePath] = dialog.showOpenDialogSync(this.win, {
            properties: ['openFile'],
            filters: [{
                name: "Images", extensions: extensions
            }]
        })
        const size = fs.statSync(filePath).size;
        const name = path.parse(filePath).base;
        const splits= name.split('.');   //原来的方法如果文字出现小数点则出错
        const type = splits[splits.length-1];  
        const data = {
            path: filePath,
            size,
            name,
            type
        };
        if (SUPPORT_IMAGE_TYPE.find(v => type.toLocaleLowerCase().includes(v))) {
            const fileContent = await fs.readFileSync(filePath);
            data.fileContent = fileContent;
        }
        event.reply(GET_FILE_INFO_CALLBACK, {
            triggerType: SELECT_FILES,
            data
        })
    }
}

module.exports = IPC;